#include "FKWorldReferent.h"

//#include <QEvent>
//#include <QMouseEvent>
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
//#include <QOpenGLContext>
#include <QSize>
//#include <QWindow>

//#include "FKActorsModel.h"
#include "FKDrawModel.h"
#include "FKSimpleDrawModel.h"
#include "FKDisplayReferent.h"
#include "FKSDM.h"

//#include "FKEventNames.h"
#include "FKLogger.h"

FKWorldReferent::FKWorldReferent(QObject* parent):QObject(parent),_cameraCalculated(false),_size(1,1),_oldSize(0,0),_isLoading(false),_isLoaded(false){
    FK_CBEGIN
//    FKDisplayReferent::setWorldReferent(this);
    FKDrawModel* m=new FKSimpleDrawModel(FKSDM::quad,0.3f,0.2f,0.02f,FKSDM::quad);
    addModel(m);
//    _actorsModel=0;
    _pickingFBP=0;
    FK_CEND
}

FKWorldReferent::~FKWorldReferent(){
    FK_DBEGIN
    resetModels();
    FK_DEND
}

void FKWorldReferent::addModel(FKDrawModel* model){
    _drawModels[model->modelName()]=model;
}

void FKWorldReferent::resetModels(){
    foreach(FKDrawModel* model,_drawModels)model->deleteLater();
    _drawModels.clear();
}

void FKWorldReferent::calculateCamera(){
    _cameraViewMat.setToIdentity();
    _cameraViewMat.translate(_cameraPosition);
    _cameraViewMat.rotate(_cameraRotation);
    QVector3D cameraUpDirection = _cameraViewMat * QVector3D(0, 1, 0);
    _cameraViewMat.lookAt(QVector3D(0.0,0.0,0.0), QVector3D(0, 0, -1.0), cameraUpDirection);
    _cameraCalculated=true;
}

void FKWorldReferent::moveCamera(QVector3D v){
    _cameraCalculated=false;
    _cameraPosition-=v;
}

void FKWorldReferent::turnCamera(QQuaternion q){
    _cameraCalculated=false;
    _cameraRotation=q * _cameraRotation;
}

QMatrix4x4 FKWorldReferent::worldViewMatrix(){
    if(!_cameraCalculated)calculateCamera();
    return _cameraViewMat;
}

void FKWorldReferent::resize(QSize size){
    _size=size;
}

void FKWorldReferent::applyResize(){
    _oldSize=_size;
    glViewport(0, 0, _oldSize.width(), _oldSize.height());
    _pMat.setToIdentity();
    _pMat.perspective(60.0f, (float) _oldSize.width() / (float) _oldSize.height(), 0.001f, 1000);
    if(_pickingFBP) delete _pickingFBP;
    _pickingFBP=new QOpenGLFramebufferObject(_oldSize,QOpenGLFramebufferObject::Depth,GL_TEXTURE_2D);
}

void FKWorldReferent::areaClicked(QPoint pos){
    _lastClicked=pos;
}

qint32 FKWorldReferent::getObject(const QPoint &p){
    FK_MLOGV("object capturing",p)
    QImage colorBuffer(_colorBuffer);
//    colorBuffer.save("C:/Users/Fajrega Koto/Desktop/Img.jpeg");
    qint32 obj=qRed(colorBuffer.pixel(p));
    if(obj==255)obj=-1;
    return obj;
}

void FKWorldReferent::draw(){
    glClearColor(1.0f,1.0f,81.0f/255.0f,1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    if(!_isLoaded)return;
    if(_oldSize!=_size)applyResize();
    QMatrix4x4 pMat(_pMat);
    QMatrix4x4 vMat(worldViewMatrix());
    foreach(FKDrawModel* model, getModels()){
        drawModelObjects(model,pMat,vMat);
    }
    pickingBuffer()->bind();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    foreach(FKDrawModel* model, getModels()){
        pickModelObjects(model,pMat,vMat);
    }
    QPoint lastClicked(_lastClicked);
    _lastClicked=QPoint();
    if(!lastClicked.isNull()){
        _colorBuffer=_pickingFBP->toImage();
        emit mouseClicked(lastClicked,getObject(lastClicked));
    }
    pickingBuffer()->release();
}

void FKWorldReferent::drawModelObjects(FKDrawModel* model, const QMatrix4x4& pMat, const QMatrix4x4& vMat){
    model->program()->bind();
    while(model->drawNextObject(pMat,vMat));
    model->program()->release();
}

void FKWorldReferent::pickModelObjects(FKDrawModel* model, const QMatrix4x4& pMat, const QMatrix4x4& vMat){
    model->pickingProgram()->bind();
    while(model->pickNextObject(pMat,vMat));
    model->pickingProgram()->release();
}

void FKWorldReferent::loadScene(){
    foreach(FKDrawModel* m,_drawModels){
        m->initModel();
    }
    glEnable(GL_DEPTH_TEST);
}

void FKWorldReferent::loadSceneRequest(){
    _isLoading=true;
}

void FKWorldReferent::loadSceneCall(){
    if(_isLoading){
        _isLoading=false;
        loadScene();
        _isLoaded=true;
        emit sceneLoadingComplete();
    }
}
